#include "../../stdafx.h"
#include "uigifanim.h"

namespace uilib
{
	CGifAnimUI::CGifAnimUI(void)
	{
		m_pGifImage = NULL;
		m_pPropertyItem = NULL;
		m_nFrameCount = 0;
		m_nFramePosition = 0;
		m_bIsAutoPlay = true;
		m_bIsAutoSize = false;
		m_bIsPlaying = false;
		m_pStream = NULL;
	}


	CGifAnimUI::~CGifAnimUI(void)
	{
		DeleteGif();
		m_pManager->KillTimer(this, EVENT_TIEM_ID);

	}

	LPSTRING CGifAnimUI::GetClass() const
	{
		return DUI_CTR_GIFANIM;
	}

	LPVOID CGifAnimUI::GetInterface(LPSTRING pstrName)
	{
		if (_tcscmp(pstrName, DUI_CTR_GIFANIM) == 0) return static_cast<CGifAnimUI*>(this);
		return CControlUI::GetInterface(pstrName);
	}

	void CGifAnimUI::DoInit()
	{
		InitGifImage();
	}

	bool CGifAnimUI::DoPaint(HDC hDC, const RECT& rcPaint, CControlUI* pStopControl)
	{
		if (NULL == m_pGifImage)
		{
			InitGifImage();
		}
		DrawFrame(hDC);
		return true;
	}

	void CGifAnimUI::DoEvent(TEventUI& event)
	{
		if (event.Type == UIEVENT_TIMER)
			OnTimer((UINT_PTR)event.wParam);
	}

	void CGifAnimUI::SetVisible(bool bVisible /* = true */)
	{
		CControlUI::SetVisible(bVisible);
		if (bVisible)
			PlayGif();
		else
			StopGif();
	}

	void CGifAnimUI::SetAttribute(LPSTRING pstrName, LPSTRING pstrValue)
	{
		if (_tcscmp(pstrName, _T("bkimage")) == 0) SetBkImage(pstrValue);
		else if (_tcscmp(pstrName, _T("autoplay")) == 0) {
			SetAutoPlay(_tcscmp(pstrValue, _T("true")) == 0);
		}
		else if (_tcscmp(pstrName, _T("autosize")) == 0) {
			SetAutoSize(_tcscmp(pstrValue, _T("true")) == 0);
		}
		else
			CControlUI::SetAttribute(pstrName, pstrValue);
	}

	void CGifAnimUI::SetBkImage(LPSTRING pStrImage)
	{
		if (m_sBkImage == pStrImage || NULL == pStrImage) return;

		m_sBkImage = pStrImage;

		StopGif();
		DeleteGif();

		Invalidate();

	}

	LPSTRING CGifAnimUI::GetBkImage()
	{
		return m_sBkImage.GetData();
	}

	void CGifAnimUI::SetAutoPlay(bool bIsAuto)
	{
		m_bIsAutoPlay = bIsAuto;
	}

	bool CGifAnimUI::IsAutoPlay() const
	{
		return m_bIsAutoPlay;
	}

	void CGifAnimUI::SetAutoSize(bool bIsAuto)
	{
		m_bIsAutoSize = bIsAuto;
	}

	bool CGifAnimUI::IsAutoSize() const
	{
		return m_bIsAutoSize;
	}

	void CGifAnimUI::PlayGif()
	{
		if (m_bIsPlaying || m_pGifImage == NULL)
		{
			return;
		}

		long lPause = ((long*)m_pPropertyItem->value)[m_nFramePosition] * 10;
		if (lPause == 0) lPause = 100;
		m_pManager->SetTimer(this, EVENT_TIEM_ID, lPause);

		m_bIsPlaying = true;
	}

	void CGifAnimUI::PauseGif()
	{
		if (!m_bIsPlaying || m_pGifImage == NULL)
		{
			return;
		}

		m_pManager->KillTimer(this, EVENT_TIEM_ID);
		this->Invalidate();
		m_bIsPlaying = false;
	}

	void CGifAnimUI::StopGif()
	{
		if (!m_bIsPlaying)
		{
			return;
		}

		m_pManager->KillTimer(this, EVENT_TIEM_ID);
		m_nFramePosition = 0;
		this->Invalidate();
		m_bIsPlaying = false;
	}

	void CGifAnimUI::InitGifImage()
	{
		m_pGifImage = LoadGifFromFile(GetBkImage());
		if (NULL == m_pGifImage) return;
		UINT nCount = 0;
		nCount = m_pGifImage->GetFrameDimensionsCount();
		GUID* pDimensionIDs = new GUID[nCount];
		m_pGifImage->GetFrameDimensionsList(pDimensionIDs, nCount);
		m_nFrameCount = m_pGifImage->GetFrameCount(&pDimensionIDs[0]);
		int nSize = m_pGifImage->GetPropertyItemSize(PropertyTagFrameDelay);
		m_pPropertyItem = (Gdiplus::PropertyItem*) malloc(nSize);
		m_pGifImage->GetPropertyItem(PropertyTagFrameDelay, nSize, m_pPropertyItem);
		delete[] pDimensionIDs;
		pDimensionIDs = NULL;

		if (m_bIsAutoSize)
		{
			SetFixedWidth(m_pGifImage->GetWidth());
			SetFixedHeight(m_pGifImage->GetHeight());
		}
		if (m_bIsAutoPlay && nSize > 0)
		{
			PlayGif();
		}
	}

	void CGifAnimUI::DeleteGif()
	{
		if (m_pStream != NULL)
		{
			m_pStream->Release();
			m_pStream = NULL;
		}
		if (m_pGifImage != NULL)
		{
			delete m_pGifImage;
			m_pGifImage = NULL;
		}

		if (m_pPropertyItem != NULL)
		{
			free(m_pPropertyItem);
			m_pPropertyItem = NULL;
		}
		m_nFrameCount = 0;
		m_nFramePosition = 0;
	}

	void CGifAnimUI::OnTimer(UINT_PTR idEvent)
	{
		if (idEvent != EVENT_TIEM_ID)
			return;
		m_pManager->KillTimer(this, EVENT_TIEM_ID);
		this->Invalidate();

		m_nFramePosition = (++m_nFramePosition) % m_nFrameCount;

		long lPause = ((long*)m_pPropertyItem->value)[m_nFramePosition] * 10;
		if (lPause == 0) lPause = 100;
		m_pManager->SetTimer(this, EVENT_TIEM_ID, lPause);
	}

	void CGifAnimUI::DrawFrame(HDC hDC)
	{
		if (NULL == hDC || NULL == m_pGifImage) return;
		GUID pageGuid = Gdiplus::FrameDimensionTime;
		Gdiplus::Graphics graphics(hDC);
		graphics.DrawImage(m_pGifImage, m_rcItem.left, m_rcItem.top, m_rcItem.right - m_rcItem.left, m_rcItem.bottom - m_rcItem.top);
		m_pGifImage->SelectActiveFrame(&pageGuid, m_nFramePosition);
	}

	Gdiplus::Image* CGifAnimUI::LoadGifFromFile(LPSTRING pstrGifPath)
	{
		LPBYTE pData = NULL;
		DWORD dwSize = 0;

		do
		{
			CDuiString sFile = CPaintManagerUI::GetResourcePath();
			
			sFile += pstrGifPath;
			HANDLE hFile = ::CreateFile(sFile.GetData(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, \
				FILE_ATTRIBUTE_NORMAL, NULL);
			if (hFile == INVALID_HANDLE_VALUE) break;
			dwSize = ::GetFileSize(hFile, NULL);
			if (dwSize == 0)
			{
				::CloseHandle(hFile);
				break;
			}

			DWORD dwRead = 0;
			pData = new BYTE[dwSize];
			::ReadFile(hFile, pData, dwSize, &dwRead, NULL);
			::CloseHandle(hFile);

			if (dwRead != dwSize) {
				delete[] pData;
				pData = NULL;
				break;
			}
			

		} while (0);

		while (!pData)
		{
			HANDLE hFile = ::CreateFile(pstrGifPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, \
				FILE_ATTRIBUTE_NORMAL, NULL);
			if (hFile == INVALID_HANDLE_VALUE) break;
			dwSize = ::GetFileSize(hFile, NULL);
			if (dwSize == 0)
			{
				::CloseHandle(hFile);
				break;
			}

			DWORD dwRead = 0;
			pData = new BYTE[dwSize];
			::ReadFile(hFile, pData, dwSize, &dwRead, NULL);
			::CloseHandle(hFile);

			if (dwRead != dwSize) {
				delete[] pData;
				pData = NULL;
			}
			break;
		}
		if (!pData)
		{
			return NULL;
		}

		Gdiplus::Image* pImage = LoadGifFromMemory(pData, dwSize);
		delete[] pData;
		return pImage;
	}

	Gdiplus::Image* CGifAnimUI::LoadGifFromMemory(LPVOID pBuf, size_t dwSize)
	{
		HGLOBAL hMem = ::GlobalAlloc(GMEM_MOVEABLE, dwSize);
		BYTE* pMem = (BYTE*)::GlobalLock(hMem);

		memcpy(pMem, pBuf, dwSize);
		::GlobalUnlock(hMem);

		::CreateStreamOnHGlobal(hMem, TRUE, &m_pStream);
		Gdiplus::Image *pImg = Gdiplus::Image::FromStream(m_pStream);
		if (!pImg || pImg->GetLastStatus() != Gdiplus::Ok)
		{
			m_pStream->Release();
			m_pStream = NULL;
			return 0;
		}
		return pImg;
	}
}
